package com.jf.cloud.order.config.sharding;

import com.jf.cloud.order.constant.OrderShardingTableType;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.shardingsphere.api.sharding.complex.ComplexKeysShardingAlgorithm;
import org.apache.shardingsphere.api.sharding.complex.ComplexKeysShardingValue;

import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 自定义复合分表策略算法
 * @author zz
 * @version 1.0
 */
public class CustomTableComplexKeysShardingAlgorithm implements ComplexKeysShardingAlgorithm<Long> {

    /**
     * 分片键优先级依次为：
     * order_id、user_id、refund_id
     * 维度，订单号、售后单号，他们的三个字段的后三位都是userid后三位
     *
     * 虽然是多字段路由，但最后都是取的userId的后三位
     *
     * @param tableNames 表名
     * @param shardingValue 分片键信息
     * @return 匹配的数据源集合
     */
    @Override
    public Collection<String> doSharding(Collection<String> tableNames,
                                         ComplexKeysShardingValue<Long> shardingValue) {
        Collection<Long> orderIds = shardingValue.getColumnNameAndShardingValuesMap().get("order_id");
        Collection<Long> orderItemIds = shardingValue.getColumnNameAndShardingValuesMap().get("order_item_id");
        Collection<Long> orderInvoiceIds = shardingValue.getColumnNameAndShardingValuesMap().get("order_invoice_id");
        Collection<Long> giveawayOrderItemIds = shardingValue.getColumnNameAndShardingValuesMap().get("giveaway_order_item_id");
        Collection<Long> settlementIds = shardingValue.getColumnNameAndShardingValuesMap().get("settlement_id");
        Collection<Long> userIds = shardingValue.getColumnNameAndShardingValuesMap().get("user_id");
        Collection<Long> refundIds = shardingValue.getColumnNameAndShardingValuesMap().get("refund_id");
        Collection<Long> orderAddrIds = shardingValue.getColumnNameAndShardingValuesMap().get("order_addr_id");
        Collection<Long> orderPreSaleInfoIds = shardingValue.getColumnNameAndShardingValuesMap().get("order_pre_sale_info_id");
        Collection<Long> purchaseOrderIds = shardingValue.getColumnNameAndShardingValuesMap().get("purchase_order_id");
        Collection<Long> purchaseItemIds = shardingValue.getColumnNameAndShardingValuesMap().get("purchase_item_id");
        Collection<Long> purchaseOrderAddrIds = shardingValue.getColumnNameAndShardingValuesMap().get("purchase_order_addr_id");
        Collection<Long> orderSelfStationIds = shardingValue.getColumnNameAndShardingValuesMap().get("order_self_station_id");
        Collection<Long> orderVirtualInfoIds = shardingValue.getColumnNameAndShardingValuesMap().get("order_virtual_info_id");
        OrderShardingTableType orderShardingTableType = OrderShardingTableType.DEFAULT;
        // 退款业务表
        if (shardingValue.getLogicTableName().contains(OrderShardingTableType.REFUND.getName())) {
            orderShardingTableType = OrderShardingTableType.REFUND;
        } else if (shardingValue.getLogicTableName().contains(OrderShardingTableType.PURCHASE.getName())) {
            orderShardingTableType = OrderShardingTableType.PURCHASE;
        }

        if (CollectionUtils.isNotEmpty(orderIds)) {
            return getTableNames(tableNames, orderIds, orderShardingTableType);
        }
        if (CollectionUtils.isNotEmpty(orderItemIds)) {
            return getTableNames(tableNames, orderItemIds, orderShardingTableType);
        }
        if (CollectionUtils.isNotEmpty(orderInvoiceIds)) {
            return getTableNames(tableNames, orderInvoiceIds, orderShardingTableType);
        }
        if (CollectionUtils.isNotEmpty(giveawayOrderItemIds)) {
            return getTableNames(tableNames, giveawayOrderItemIds, orderShardingTableType);
        }
        if (CollectionUtils.isNotEmpty(settlementIds)) {
            return getTableNames(tableNames, settlementIds, orderShardingTableType);
        }
        if (CollectionUtils.isNotEmpty(userIds)) {
            return getTableNames(tableNames, userIds, orderShardingTableType);
        }
        if (CollectionUtils.isNotEmpty(refundIds)) {
            return getTableNames(tableNames, refundIds, orderShardingTableType);
        }
        if (CollectionUtils.isNotEmpty(orderAddrIds)) {
            return getTableNames(tableNames, orderAddrIds, orderShardingTableType);
        }
        if (CollectionUtils.isNotEmpty(orderPreSaleInfoIds)) {
            return getTableNames(tableNames, orderPreSaleInfoIds, orderShardingTableType);
        }

        if (CollectionUtils.isNotEmpty(purchaseOrderIds)) {
            return getTableNames(tableNames, purchaseOrderIds, orderShardingTableType);
        }
        if (CollectionUtils.isNotEmpty(purchaseItemIds)) {
            return getTableNames(tableNames, purchaseItemIds, orderShardingTableType);
        }
        if (CollectionUtils.isNotEmpty(purchaseOrderAddrIds)) {
            return getTableNames(tableNames, purchaseOrderAddrIds, orderShardingTableType);
        }
        if (CollectionUtils.isNotEmpty(orderSelfStationIds)) {
            return getTableNames(tableNames,orderSelfStationIds, orderShardingTableType);
        }
        if (CollectionUtils.isNotEmpty(orderVirtualInfoIds)) {
            return getTableNames(tableNames, orderVirtualInfoIds, orderShardingTableType);
        }
        return null;
    }

    /**
     * 获取真实的表名
     * @param columnValues 分片键的值
     * @return 匹配的表名集合
     */
    private Set<String> getTableNames(Collection<String> tableNames, Collection<Long> columnValues, OrderShardingTableType orderShardingTableType) {
        // 因为拿到的值可能是long类型
        List<String> columnValueStrs = columnValues.stream().map(String::valueOf).collect(Collectors.toList());
        Set<String> set = new HashSet<>();
        for(String columnValue : columnValueStrs) {
            // 获取用户ID后三位
            String valueSuffix = (columnValue.length() < 3) ? columnValue : columnValue.substring(columnValue.length() - 3);
            String databaseSuffix = ShardingAlgorithmHelper.getTableSuffix(Integer.parseInt(valueSuffix), orderShardingTableType);
            for(String tableName : tableNames) {
                if(tableName.endsWith(databaseSuffix)) {
                    set.add(tableName);
                }
            }
        }
        return set;
    }
    private Set<String> getTableNames(Collection<String> tableNames, Collection<Long> columnValues) {
        return getTableNames(tableNames, columnValues, OrderShardingTableType.DEFAULT);
    }
}
